
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.image.BufferedImage;
import javax.swing.JPanel;

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
/**
 *
 * @author Alexander Velichkov
 */
public class Mandelbrot extends FractalPanel implements java.awt.event.MouseMotionListener, MouseWheelListener {

    private JPanel jpPaint;
    private static int LIMIT = 20;
    private int mouseX;
    private int mouseY;
    private BufferedImage canvas;
    private Complex c;
    private Complex z;
    private ITweakable julia;
    private double leftLimit;
    private double rightLimit;
    private double topLimit;
    private double bottomLimit;

    Mandelbrot() {
        this.addMouseMotionListener(this);
        this.addMouseWheelListener(this);
        leftLimit = -2;
        rightLimit = 2;
        topLimit = 2;
        bottomLimit = -2;
    }

    public void setJulia(ITweakable julia) {
        this.julia = julia;
    }

    public void init() {
        canvas = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
    }

    public void regenerate() {
        for (int x = 0; x < getWidth(); x++) {
            for (int y = 0; y < getHeight(); y++) {
                double newX = mandelbrotX(x);
                double newY = mandelbrotY(y);
                z = new Complex(0, 0);
                c = new Complex(newX, newY);
                for (int l = 0; l < LIMIT; l++) {
                    z = z.times(z);
                    z = z.plus(c);
                    if (z.dist() > 2) {
                        Color color;
                        if (l <= LIMIT / 2) {
                            color = new Color(0, 0, (int) (50 + (255.0 - 50.0) / (LIMIT / 2) * l));
                        } else {
                            int val = (int) ((l - LIMIT / 2.0) / (LIMIT / 2) * 255);
                            color = new Color(val, val, 255);
                        }
                        int fractalColor = color.getRGB();
                        canvas.setRGB(x, y, fractalColor);
                        break;
                    }
                    if (l == LIMIT - 1) {
                        canvas.setRGB(x, y, 0);
                    }
                }
            }
        }
        repaint();
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        //g.drawString("(" + mouseX + "," + mouseY + ")", 5, 15);
        //g.drawString("(" + mandelbrotX(mouseX) + "," + mandelbrotY(mouseY) + ")", 5, 25);
        if (canvas != null) {
            g.drawImage(canvas, 0, 0, null);
        }
    }

    public void mouseDragged(MouseEvent me) {
        double deltaX = (double) (mouseX - me.getX()) / getWidth() * (rightLimit - leftLimit);
        leftLimit += deltaX;
        rightLimit += deltaX;
        double deltaY = (double) (mouseY - me.getY()) / getHeight() * (topLimit - bottomLimit);
        topLimit += deltaY;
        bottomLimit += deltaY;
        mouseX = me.getX();
        mouseY = me.getY();
        regenerate();
    }

    public void mouseMoved(MouseEvent me) {
        mouseX = me.getX();
        mouseY = me.getY();
        julia.tweakParam(new Complex(mandelbrotX(mouseX), mandelbrotY(mouseY)));
    }

    public double mandelbrotX(double x) {
        double newX = x / getWidth() * (rightLimit - leftLimit);
        return newX + leftLimit;
    }

    public double mandelbrotY(double y) {
        double newY = y / getHeight() * (topLimit - bottomLimit);
        return newY + bottomLimit;
    }

    public void mouseWheelMoved(MouseWheelEvent mwe) {
        if (mwe.getWheelRotation() == 1) {
            leftLimit += 0.1;
            rightLimit -= 0.1;
            topLimit -= 0.1;
            bottomLimit += 0.1;
            regenerate();
        } else {
            leftLimit -= 0.1;
            rightLimit += 0.1;
            topLimit += 0.1;
            bottomLimit -= 0.1;
            regenerate();
        }
    }
}
